/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2020-12-14     Ghazigq     the first version
 */


#include "gbkAndUtf.h"

//#ifdef PKG_USING_GBK2UTF8

//B0A1-F7FE
//gbk 转 unicode
const unsigned short gs_gbk2uni_table[] =
{
  #include "gbk2unicode.c"
};


//unicode 转 gbk
//范围 0x4e02, 20900
const unsigned short gs_uni2gbk_table0[] =
{
   #include "unicode2gbk.c"
};

//unicode 转gbk
//起始 0xe4c6, 长度 1222
const unsigned short gs_uni2gbk_table1[] =
{
    #include "unicode2gbk_2.c"
};

/***********************************************************
 * 函数名称：gbk2uni
 * 功能描述：gbk 转 unicode (8140-FEFE)
 * 输入参数： ch  高字节
 *        cl  低字节
 * 输出参数：无
 * 返 回 值：  错误返回 0, 其它正确
 ***********************************************************/
unsigned short gbk2uni(unsigned char ch, unsigned char cl)
{
    ch -= 0x81;
    cl -= 0x40;

    return ((ch < 0x7E) && (cl < 0xBF)) ? gs_gbk2uni_table[ch * 0xBF + cl] : 0;
}

/***********************************************************
 * 函数名称：uni2gbk
 * 功能描述： unicode 转  gbk
 * 输入参数： uni unicode 字符
 * 输出参数：无
 * 返 回 值：  错误返回 0, 其它正确
 ***********************************************************/
 
unsigned short uni2gbk2(unsigned short uni)
{
    uni -= 0x4E02;

    if (uni < ARRAY_SIZE_A(gs_uni2gbk_table0))
    {
        return gs_uni2gbk_table0[uni];
    }

    uni -= 0xE4C6 - 0x4E02;

    if (uni < ARRAY_SIZE_A(gs_uni2gbk_table1))
    {
        return gs_uni2gbk_table1[uni];
    }

    return 0;
}



// UTF-8
//1字节  7位     0xxxxxxx
//2字节  12位  110xxxxx 10xxxxxx
//3字节  16位   1110xxxx 10xxxxxx 10xxxxxx
//4字节   21位 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


/***********************************************************
 * 函数名称：gbk2utf8
 * 功能描述：将 gbk转为 utf8
 * 输入参数：pin_buf 输入缓冲区
 *       in_len  输入长度
 * 输出参数：ptr 成功后的起始位置(malloc产生),(数据末尾加上'0')
 * 返 回 值：  转换后的长度, < 0 失败,其它成功
 ***********************************************************/
int gbk2utf8(char *ptr, void *pin_buf, int in_len)
{
	unsigned char *pout = ptr;
    unsigned char *pin = (unsigned char *)pin_buf;
    unsigned char *pend = pin + in_len;
    unsigned char h =0; 
    if ( (pin_buf == NULL) || (in_len < 0))
    {
        return -1;
    }

    //unsigned char *ps = (unsigned char *)malloc(in_len * 3 + 1);

    while (pin < pend)
    {
        h = *pin++;

        if (!(h & 0x80))
        {
            *ptr++ = h;
            continue;
        }

        if (pin + 1 > pend)
        {
            return -1;
        }

        unsigned short uniode = gbk2uni(h, *pin++);

        if (uniode == 0)
        {
            return -1;
        }

        *ptr++ = 0xE0 | ((uniode >> 12) & 0x0f);
        *ptr++ = 0x80 | ((uniode >> 6) & 0x3f);
        *ptr++ = 0x80 | (uniode & 0x3f);
    }


    return ((unsigned long long)ptr)-((unsigned long long)pout);
}


/***********************************************************
 * 函数名称：utf82gbk
 * 功能描述：将utf8转为gbk
 * 输入参数：pin_buf 输入缓冲区
 *       in_len  输入长度
 * 输出参数：ptr 成功后的起始位置(malloc产生),(数据末尾加上'0')
 * 返 回 值：  转换后的长度, < 0 失败,其它成功
 ***********************************************************/
int utf82gbk(char *ptr, void *pin_buf, int in_len)
{
    unsigned char *pout = ptr;
    unsigned char *pin = (unsigned char *)pin_buf;
    unsigned char *pend = pin + in_len;
    unsigned char h = 0,mid = 0, end = 0;
    unsigned short uniode = 0, gbk = 0;
    if ( (pin_buf == NULL) || (in_len < 0))
    {
        return -1;
    }
    
    while (*pin)
    {
        h = *pin++;
        if (!(h & 0x80))
        {
            *pout++ = h;
            continue;
        }

        if ((pin + 2) > pend)
        {
            return -1;
        }

        mid = pin[0];
        end = pin[1];

        if (((h & 0xF0) != 0xE0) || ((mid & 0xC0) != 0x80) || ((end & 0xC0) != 0x80))
        {
            return -1;
        }

        uniode = ((unsigned short)h << 12) | ((unsigned short)(mid & 0x3f) << 6) | (end & 0x3f);
        gbk = uni2gbk2(uniode);

        if (gbk == 0)
        {
            return -1;
        }
        pin += 2;
        *pout++ = gbk >> 8;
        *pout++ = gbk;
    }
    *pout = 0;
    return ((unsigned long long)pin)-((unsigned long long)pin_buf);
}

unsigned char  utf8_check(const char* str,unsigned short length)
{
    unsigned short  i = 0;
    int nBytes = 0;//UTF8可用1-6个字节编码,ASCII用一个字节
    unsigned char ch = 0;
    while(i < length)
    {
        ch = *(str + i);
        if(nBytes == 0)
        {
            if((ch & 0x80) != 0)
            {
                while((ch & 0x80) != 0)
                {
                    ch <<= 1;
                    nBytes ++;
                }
                if((nBytes < 2) || (nBytes > 6))
                {
                    return 0;
                }
                nBytes --;
            }
        }
        else
        {
            if((ch & 0xc0) != 0x80)
            {
                return 0;
            }
            nBytes --;
        }
        i ++;
    }
    return (nBytes == 0);
}

unsigned char gbk_check(const char* str,unsigned short length){
    int i  = 0;
    while (i < length)  {
        if (str[i] <= 0x7f) {
            //编码小于等于127,只有一个字节的编码，兼容ASCII
            i++;
            continue;
        } else {
            //大于127的使用双字节编码
            if  (str[i] >= 0x81 &&
                str[i] <= 0xfe &&
                str[i + 1] >= 0x40 &&
                str[i + 1] <= 0xfe &&
                str[i + 1] != 0xf7) {
                i += 2;
                continue;
            } else {
                return 0;
            }
        }
    }
    return 1;
}


unsigned char ascii_check(const char* str,unsigned short length){
    int i  = 0;
    while (i < length)  {
        if (str[i] <128) {
            //编码小于等于127,只有一个字节的编码，兼容ASCII
            i++;
        }else{
        	return 0;
		}
    }
    return 1;
}





//需要说明的是，isGBK()是通过双字节是否落在gbk的编码范围内实现的，
//而utf-8编码格式的每个字节都是落在gbk的编码范围内??
//所以只有先调用isUtf8()先判断不是utf-8编码，再调用isGBK()才有意义
unsigned char GetCoding(unsigned char* data, unsigned int len) 
{
    unsigned char coding =0;
	///*
    if (1 == utf8_check(data, len)) {//utf8
        return 1;	
	} else if (1==gbk_check(data, len)) {//GBK
		 return 2;
	} else if(1 == ascii_check(data, len)) {
		 return 3;
	}else{
         return 4;
    }
	//*/
	/*
	//不是utf8就是GBK加快编码转换速度
	if (1==utf8_check(data, len)) {//utf8	
        return 1;	
	}else return 2;
	*/
}


//#endif /* PKG_USING_GBK2UTF8 */
